package com.talkweb.osmharmony.tileprovider.util;

import com.talkweb.osmharmony.api.IMapView;
import com.talkweb.osmharmony.config.Configuration;
import com.talkweb.osmharmony.util.Log;
import ohos.account.AccountAbility;
import ohos.app.Context;
import ohos.data.DatabaseHelper;
import ohos.data.preferences.Preferences;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.UUID;

/**
 * Utility class for implementing Cloudmade authorization. See
 * http://developers.cloudmade.com/projects/show/auth
 * <p>
 * The CloudMade token is persisted because it doesn't change:
 * http://support.cloudmade.com/answers/api-keys-and-authentication
 * "you will always get the same token for the unique user id"
 */
public class CloudmadeUtil {

    public static boolean DEBUGMODE = false;
    /**
     * the meta data key in the manifest
     */
    private static final String CLOUDMADE_KEY = "CLOUDMADE_KEY";

    /**
     * the key for the id preference
     */
    private static final String CLOUDMADE_ID = "CLOUDMADE_ID";

    /**
     * the key for the token preference
     */
    private static final String CLOUDMADE_TOKEN = "CLOUDMADE_TOKEN";

    private static String mOpenHarmonyId = UUID.randomUUID().toString(); // will get real id later

    /**
     * the key retrieved from the manifest
     */
    private static String mKey = "";

    /**
     * the token
     */
    private static String mToken = "";

    private static Preferences mPreferenceEditor;

    private static String getDefaultPreferencesName(Context context) {
        return context.getBundleName() + "_preferences";
    }

    /**
     * Retrieve the key from the manifest and store it for later use.
     */
    public static void retrieveCloudmadeKey(final Context aContext) {

        mOpenHarmonyId = AccountAbility.getAccountAbility().getDistributedVirtualDeviceId();

        // get the key from the manifest
        mKey = ManifestUtil.retrieveKey(aContext, CLOUDMADE_KEY);

        // if the id hasn't changed then set the token to the previous token
        final DatabaseHelper databaseHelper = new DatabaseHelper(aContext);
        mPreferenceEditor = databaseHelper.getPreferences(getDefaultPreferencesName(aContext));
        final String id = mPreferenceEditor.getString(CLOUDMADE_ID, "");
        if (id.equals(mOpenHarmonyId)) {
            mToken = mPreferenceEditor.getString(CLOUDMADE_TOKEN, "");
            // if we've got a token we don't need the editor any more
            if (mToken.length() > 0) {
                mPreferenceEditor = null;
            }
        } else {
            mPreferenceEditor.putString(CLOUDMADE_ID, mOpenHarmonyId);
            mPreferenceEditor.flushSync();
        }

    }

    /**
     * Get the key that was previously retrieved from the manifest.
     *
     * @return the key, or empty string if not found
     */
    public static String getCloudmadeKey() {
        return mKey;
    }

    /**
     * Get the key that was previously retrieved from the manifest.
     *
     * @return the key, or empty string if not found
     */
    public static void setCloudmadeKey(String key) {
        mKey = key;
    }

    /**
     * Get the token from the Cloudmade server.
     *
     * @return the token returned from the server, or null if not found
     */
    public static String getCloudmadeToken() {

        if (mToken.length() == 0) {
            synchronized (mToken) {
                // check again because it may have been set while we were blocking
                if (mToken.length() == 0) {
                    final String url = "https://auth.cloudmade.com/token/" + mKey + "?userid=" + mOpenHarmonyId;

                    HttpURLConnection urlConnection = null;
                    BufferedReader br = null;
                    InputStreamReader is = null;
                    try {
                        final URL urlToRequest = new URL(url);
                        urlConnection = (HttpURLConnection) urlToRequest.openConnection();
                        urlConnection.setDoOutput(true);
                        urlConnection.setRequestMethod("POST");
                        urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
                        urlConnection.setRequestProperty(Configuration.getInstance().getUserAgentHttpHeader(), Configuration.getInstance().getUserAgentValue());
                        for (final Map.Entry<String, String> entry : Configuration.getInstance().getAdditionalHttpRequestProperties().entrySet()) {
                            urlConnection.setRequestProperty(entry.getKey(), entry.getValue());
                        }
                        urlConnection.connect();
                        if (DEBUGMODE) {
                            Log.d(IMapView.LOGTAG, "Response from Cloudmade auth: " + urlConnection.getResponseMessage());
                        }
                        if (urlConnection.getResponseCode() == 200) {
                            is = new InputStreamReader(urlConnection.getInputStream(), "UTF-8");
                            br = new BufferedReader(is, StreamUtils.IO_BUFFER_SIZE);
                            final String line = br.readLine();
                            if (DEBUGMODE) {
                                Log.d(IMapView.LOGTAG, "First line from Cloudmade auth: " + line);
                            }
                            mToken = line.trim();
                            if (mToken.length() > 0) {
                                mPreferenceEditor.putString(CLOUDMADE_TOKEN, mToken);
                                mPreferenceEditor.flushSync();
                                // we don't need the editor any more
                                mPreferenceEditor = null;
                            } else {
                                Log.e(IMapView.LOGTAG, "No authorization token received from Cloudmade");
                            }
                        }
                    } catch (final IOException e) {
                        Log.e(IMapView.LOGTAG, "No authorization token received from Cloudmade: " + e);
                    } finally {
                        if (urlConnection != null)
                            try {
                                urlConnection.disconnect();
                            } catch (Exception ex) {
                            }
                        if (br != null)
                            try {
                                br.close();
                            } catch (Exception ex) {
                            }
                        if (is != null)
                            try {
                                is.close();
                            } catch (Exception ex) {
                            }
                    }
                }
            }
        }

        return mToken;
    }
}
